﻿using System;
using System.Data;
using System.Linq;
using System.Xml;

namespace MySQLToMySQL
{
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                var configFileName = args[0];

                var doc = new XmlDocument();
                doc.Load(configFileName);

                var m = GetXmlNamespaceManager(doc);

                //перебор по задачам
                foreach (var task in doc.SelectNodes("//my:task", m).Cast<XmlNode>())
                {
                    //var conStrOperational = GetMySqlConnection(doc, task.Attributes["my:operational"].Value);
                    var conStrOperationalBuilder = new MySql.Data.MySqlClient.MySqlConnectionStringBuilder(GetMySqlConnection(doc, task.Attributes["my:operational"].Value));
                    conStrOperationalBuilder.ConnectionTimeout = (uint)Properties.Settings.Default.ConnectionTimeout;
                    conStrOperationalBuilder.DefaultCommandTimeout = (uint)Properties.Settings.Default.DefaultCommandTimeout;
                    var conStrOperational = conStrOperationalBuilder.GetConnectionString(true);

                    var sqlFile = task.Attributes["my:sql"].Value;
                    var cmdTxtOperational = System.IO.File.ReadAllText(sqlFile);
                    //var conStrAnalysis = GetMySqlConnection(doc, task.Attributes["my:analysis"].Value);
                    var tableName = task.Attributes["my:table"].Value;
                    var cmdTxtAnalysis = string.Format(@"SELECT * FROM {0}", tableName);
                    var conStrAnalysisBuilder = new MySql.Data.MySqlClient.MySqlConnectionStringBuilder(GetMySqlConnection(doc, task.Attributes["my:analysis"].Value));
                    conStrAnalysisBuilder.ConnectionTimeout = (uint)Properties.Settings.Default.ConnectionTimeout;
                    conStrAnalysisBuilder.DefaultCommandTimeout = (uint)Properties.Settings.Default.DefaultCommandTimeout;
                    var conStrAnalysis = conStrAnalysisBuilder.GetConnectionString(true);

                    using (var adapter = new MySql.Data.MySqlClient.MySqlDataAdapter(cmdTxtAnalysis, conStrAnalysis))
                    {
                        //команды для адаптера
                        var builder = new MySql.Data.MySqlClient.MySqlCommandBuilder(adapter);
                        adapter.InsertCommand = builder.GetInsertCommand();
                        adapter.UpdateCommand = builder.GetUpdateCommand();
                        adapter.DeleteCommand = builder.GetDeleteCommand();
                        builder = null;

                        //таблица для синхронизации
                        var dtAnalysis = new DataTable();
                        Console.WriteLine("{0}: Fill DataSource: {1} Database: {2} Table: {3}", DateTime.Now, adapter.SelectCommand.Connection.DataSource, adapter.SelectCommand.Connection.Database, tableName);
                        adapter.Fill(dtAnalysis);

                        //очистить таблицу
                        foreach (var row in dtAnalysis.AsEnumerable().ToArray())
                        {
                            row.Delete();
                        }

                        using (var conn = new MySql.Data.MySqlClient.MySqlConnection(conStrOperational))
                        {
                            using (var cmd = new MySql.Data.MySqlClient.MySqlCommand(cmdTxtOperational, conn))
                            {
                                conn.Open();
                                using (var reader = cmd.ExecuteReader())
                                {
                                    //Console.WriteLine("{0}: DataSource: {1} Database: {2} CommandText:", DateTime.Now, conn.DataSource, conn.Database);
                                    //Console.WriteLine(cmd.CommandText);
                                    Console.WriteLine("{0}: Execute DataSource: {1} Database: {2} SQL: {3}", DateTime.Now, conn.DataSource, conn.Database, sqlFile);
                                    //заполнить строками из оперативной БД
                                    dtAnalysis.Load(reader, LoadOption.Upsert);
                                }
                                conn.Close();
                            }
                        }

                        Console.WriteLine("{0}: Update DataSource: {1} Database: {2} Table: {3}", DateTime.Now, adapter.SelectCommand.Connection.DataSource, adapter.SelectCommand.Connection.Database, tableName);
                        //сохранить в аналитической БД
                        adapter.Update(dtAnalysis);

                        dtAnalysis = null;
                    }
                }
            }
            catch (Exception ex)
            {
                //TODO не прерывать
                Console.WriteLine("{0}: Error:", DateTime.Now);
                Console.WriteLine(ex.Message);
            }
            finally
            {
                //TODO добавить счётчик ошибок
                Console.WriteLine("{0}: Press any key...", DateTime.Now);
                Console.ReadKey();
            }
        }

        static XmlNamespaceManager GetXmlNamespaceManager(XmlDocument doc)
        {
            var m = new XmlNamespaceManager(doc.Schemas.NameTable);
            m.AddNamespace(doc.DocumentElement.Prefix, doc.DocumentElement.NamespaceURI);
            return m;
        }

        static string GetMySqlConnection(XmlDocument doc, string connectionName)
        {
            var m = GetXmlNamespaceManager(doc);
            var xmlConnection = doc.SelectSingleNode(string.Format("//my:connection[text()='{0}']", connectionName), m);

            var builder = new MySql.Data.MySqlClient.MySqlConnectionStringBuilder()
            {
                Server = xmlConnection.Attributes["my:server"].Value,
                Database = xmlConnection.Attributes["my:database"].Value,
                UserID = xmlConnection.Attributes["my:user_id"].Value,
                Password = xmlConnection.Attributes["my:password"].Value
            };

            return builder.ConnectionString;
        }
    }
}